import os
from enum import Enum
from tools.bfd.const import *

try:
    lib_bfd = cdll.LoadLibrary('/usr/local/lib/libbfd-2.34.so')
except:
    raise Exception("get libbfd.so error or import error ")

# 公共基础变量
init_end = False


class bfd_direction(Enum):
    no_direction = 0
    read_direction = 1
    write_direction = 2
    both_direction = 3


class bfd_plugin_format(Enum):
    bfd_plugin_unknown = 0,
    bfd_plugin_yes = 1,
    bfd_plugin_no = 2


class bfd_format(Enum):
    bfd_unknown = 0
    bfd_object = 1,
    bfd_archive = 2,
    bfd_core = 3,
    bfd_type_end = 4


class bfd_build_id(Structure):
    _fields_ = [("size", bfd_size_type), ("data", bfd_byte)]


class bfd(Structure):  # BFD 结构体
    pass


class _link(Union):
    _fields_ = [
        (r'next', POINTER(bfd)),
        (r'hash', POINTER(bfd_link_hash_table)),
    ]


# 后端处理使用到的数据
class _tdata(Union):
    _fields_ = [
        ("aout_data", POINTER(aout_data_struct)),
        ("aout_ar_data", POINTER(artdata)),
        ("coff_obj_data", POINTER(coff_tdata)),
        ("pe_obj_data", POINTER(pe_tdata)),
        ("xcoff_obj_data", POINTER(xcoff_tdata)),
        ("ecoff_obj_data", POINTER(ecoff_tdata)),
        ("srec_data", POINTER(srec_data_struct)),
        ("verilog_data", POINTER(verilog_data_struct)),
        ("ihex_data", POINTER(ihex_data_struct)),
        ("tekhex_data", POINTER(tekhex_data_struct)),
        ("elf_obj_data", POINTER(elf_obj_tdata)),
        ("mmo_data", POINTER(mmo_data_struct)),
        ("sun_core_data", POINTER(sun_core_struct)),
        ("sco5_core_data", POINTER(sco5_core_struct)),
        ("trad_core_data", POINTER(trad_core_struct)),
        ("som_data", POINTER(som_data_struct)),
        ("hpux_core_data", POINTER(hpux_core_struct)),
        ("hppabsd_core_data", POINTER(hppabsd_core_struct)),
        ("sgi_core_data", POINTER(sgi_core_struct)),
        ("lynx_core_data", POINTER(lynx_core_struct)),
        ("osf_core_data", POINTER(osf_core_struct)),
        ("cisco_core_data", POINTER(cisco_core_struct)),
        ("versados_data", POINTER(versados_data_struct)),
        ("netbsd_core_data", POINTER(netbsd_core_struct)),
        ("mach_o_data", POINTER(mach_o_data_struct)),
        ("mach_o_fat_data", POINTER(mach_o_fat_data_struct)),
        ("plugin_data", POINTER(plugin_data_struct)),
        ("pef_data", POINTER(bfd_pef_data_struct)),
        ("pef_xlib_data", POINTER(bfd_pef_xlib_data_struct)),
        ("sym_data", POINTER(bfd_sym_data_struct)),
        (r'any', c_void_p)
    ]


bfd._fields_ = [
    (r'filename', c_char_p),
    (r'xvec', POINTER(bfd_target)),
    (r'iostream', c_void_p),
    (r'iovec', POINTER(bfd_iovec)),
    (r'lru_prev', POINTER(bfd)),
    (r'lru_next', POINTER(bfd)),
    (r'where', ufile_ptr),
    (r'mtime', c_long),
    (r'id', c_uint),
    (r'flags', flagword),
    (r'format', c_int, 3),
    (r'direction', c_int, 2),
    (r'cacheable', c_uint, 1),
    (r'target_defaulted', c_uint, 1),
    (r'opened_once', c_uint, 1),
    (r'mtime_set', c_uint, 1),
    (r'no_export', c_uint, 1),
    (r'output_has_begun', c_uint, 1),
    (r'has_armap', c_uint, 1),
    (r'is_thin_archive', c_uint, 1),
    (r'no_element_cache', c_uint, 1),
    (r'selective_search', c_uint, 1),
    (r'is_linker_output', c_uint, 1),
    (r'is_linker_input', c_uint, 1),
    (r'plugin_format', c_uint, 2),
    (r'lto_output', c_uint, 1),
    (r'lto_slim_object', c_uint, 1),
    (r'plugin_dummy_bfd', POINTER(bfd)),
    (r'origin', ufile_ptr),
    (r'proxy_origin', ufile_ptr),
    (r'section_htab', bfd_hash_table),
    (r'sections', POINTER(bfd_section)),
    (r'section_last', POINTER(bfd_section)),
    (r'section_count', c_uint),
    (r'archive_pass', c_int),
    (r'start_address', bfd_vma),
    (r'outsymbols', POINTER(POINTER(bfd_symbol))),
    (r'symcount', c_uint),
    (r'dynsymcount', c_uint),
    (r'arch_info', POINTER(bfd_arch_info)),
    (r'size', ufile_ptr),
    (r'arelt_data', c_void_p),
    (r'my_archive', POINTER(bfd)),
    (r'archive_next', POINTER(bfd)),
    (r'archive_head', POINTER(bfd)),
    (r'nested_archives', POINTER(bfd)),
    (r'link', _link),
    (r'tdata', _tdata),
    (r'usrdata', c_void_p),
    (r'memory', c_void_p),
    (r'build_id', bfd_build_id),

]


class bfd_error(Enum):
    bfd_error_no_error = 0
    bfd_error_system_call = 1
    bfd_error_invalid_target = 2
    bfd_error_wrong_format = 3
    bfd_error_wrong_object_format = 4
    bfd_error_invalid_operation = 5
    bfd_error_no_memory = 6
    bfd_error_no_symbols = 7
    bfd_error_no_armap = 8
    bfd_error_no_more_archived_files = 9
    bfd_error_malformed_archive = 10
    bfd_error_missing_dso = 11
    bfd_error_file_not_recognized = 12
    bfd_error_file_ambiguously_recognized = 13
    bfd_error_no_contents = 14
    bfd_error_nonrepresentable_section = 15
    bfd_error_no_debug_section = 16
    bfd_error_bad_value = 17
    bfd_error_file_truncated = 18
    bfd_error_file_too_big = 19
    bfd_error_sorry = 20
    bfd_error_on_input = 21
    bfd_error_invalid_error_code = 22


# 函数定义
lib_bfd.bfd_init.argtypes, lib_bfd.bfd_init.rstype = [], c_uint
lib_bfd.bfd_openr.argtypes = [c_char_p, c_char_p]
lib_bfd.bfd_openr.rstype = POINTER(bfd)

# 等效C语言数据类型
NULL = None


class Lib_BFD(object):
    file_bfd = None
    file_name = None

    def __init__(self, file=None):
        global init_end
        if not file:
            raise Exception("fie = None")
        self.file_name = file
        if not init_end:
            lib_bfd.bfd_init()
            init_end = True
        self.file_bfd = lib_bfd.bfd_openr(file.encode(), NULL)
